/*
* Poppy Game Engine - https://pgetemplate.googlecode.com/svn/
* -----------------------------------------------------------------------
* Licensed under the BSD license, see LICENSE in PSPSDK root for details.
*
* Copyright (c) 2008 Poppy
*/

#include "stdafx.h"
#include "CFileStream.h"

namespace PGESystem
{

	class FileReader : public CBinaryStream
	{
	public:
		FileReader( const char* filename )
		{
			m_pFileName = filename;
			m_hFile = PGE_OpenFile( m_pFileName, PGE_FILE_READ_ONLY );
			m_dLength = PGE_Seek32( m_hFile, 0, PGE_SEEK_END );
			PGE_Seek32( m_hFile, 0, PGE_SEEK_SET );
		}

		virtual void Seek(int pos, PGE_WHENCE whence)
		{
			PGE_Seek32( m_hFile, pos, whence );
		}

		virtual int  GetPosition()
		{
			return PGE_Seek32( m_hFile, 0, PGE_SEEK_CUR );
		}

		virtual int GetLength()
		{
			return m_dLength;
		}

		virtual int BinaryRead(void * buffer, unsigned int size)
		{
			return PGE_ReadBuffer( m_hFile, buffer, (int)size );
		}

		virtual int BinaryWrite(void * buffer, unsigned int size)
		{
			return 0;
		}

		virtual int Read(char * buffer)
		{
			int i(0);
			while(1)
			{
				if( PGE_ReadBuffer( m_hFile, buffer+i, 1 ) )
				{
					if( buffer[i] == 0 ) break;
				}
				else
				{
					buffer[i] = 0;
					break;
				}
				++i;
			}
			return i+1;
		}

		virtual int Write(char * buffer)
		{
			return 0;
		}

		virtual ~FileReader()
		{
			PGE_CloseFile( m_hFile );
		}

	protected:
		const char*			m_pFileName;
		PGE_FILE_HANDLE		m_hFile;
		int					m_dLength;

	};

	class FileBufferReader : public CBinaryStream
	{
	public:

		FileBufferReader( const char* filename, unsigned int buffersize )
		{
			m_pFileName = filename;
			m_dBufferSize = buffersize;
			m_dBufferPointer = 0;
			m_dBufferUse = 0;
			m_pBuffer = new char[m_dBufferSize];
			m_hFile = PGE_OpenFile( m_pFileName, PGE_FILE_READ_ONLY );
			m_dLength = PGE_Seek32( m_hFile, 0, PGE_SEEK_END );
			PGE_Seek32( m_hFile, 0, PGE_SEEK_SET );
			m_dBufferUse = PGE_ReadBuffer( m_hFile, m_pBuffer, m_dBufferSize );
		}

		virtual int GetLength()
		{
			return m_dLength;
		}

		virtual int BinaryRead(void * buffer, unsigned int size)
		{
			if( m_dFilePointer >= m_dLength )
			{
				return 0;
			}
			if( (m_dFilePointer < m_dBufferPointer)||(m_dFilePointer >= m_dBufferPointer+m_dBufferUse) )
			{
				PGE_Seek32( m_hFile, m_dFilePointer, PGE_SEEK_SET );
				m_dBufferPointer = m_dFilePointer;
				m_dBufferUse = PGE_ReadBuffer( m_hFile, m_pBuffer, m_dBufferSize );
			}
			unsigned int availsize;
			register int res(0);
			register unsigned int i; 
			while(1)
			{
				availsize = m_dBufferUse + m_dBufferPointer - m_dFilePointer;
				if( size <= availsize )
				{
					for( i = 0; i < size; i++ )
					{
						((char*)buffer)[res++] = m_pBuffer[ (m_dFilePointer++) - m_dBufferPointer ];
					}
					return res;
				}
				else
				{
					size -= availsize;
					for( i = 0; i < availsize; i++ )
					{
						((char*)buffer)[res++] = m_pBuffer[ (m_dFilePointer++) - m_dBufferPointer ];
					}
					if( m_dFilePointer >= m_dLength )
					{
						return res;
					}
					PGE_Seek32( m_hFile, m_dFilePointer, PGE_SEEK_SET );
					m_dBufferPointer = m_dFilePointer;
					m_dBufferUse = PGE_ReadBuffer( m_hFile, m_pBuffer, m_dBufferSize );
				}

			}
			return res;
		}

		virtual int BinaryWrite(void * buffer, unsigned int size)
		{
			return 0;
		}

		virtual int Read(char * buffer)
		{
			if( m_dFilePointer >= m_dLength )
			{
				return 0;
			}
			if( (m_dFilePointer < m_dBufferPointer)||(m_dFilePointer >= m_dBufferPointer+m_dBufferUse) )
			{
				PGE_Seek32( m_hFile, m_dFilePointer, PGE_SEEK_SET );
				m_dBufferPointer = m_dFilePointer;
				m_dBufferUse = PGE_ReadBuffer( m_hFile, m_pBuffer, m_dBufferSize );
			}
			unsigned int availsize;
			register int res(0);
			register unsigned int i;
			while(1)
			{
				availsize = m_dBufferUse + m_dBufferPointer - m_dFilePointer;
				for( i = 0; i < availsize; i++ )
				{
					buffer[res++] = m_pBuffer[ (m_dFilePointer++) - m_dBufferPointer ];
					if( buffer[res-1] == 0 ) return res;
				}
				if( m_dFilePointer >= m_dLength )
				{
					buffer[res++] = 0;
					return res;
				}
				PGE_Seek32( m_hFile, m_dFilePointer, PGE_SEEK_SET );
				m_dBufferPointer = m_dFilePointer;
				m_dBufferUse = PGE_ReadBuffer( m_hFile, m_pBuffer, m_dBufferSize );
			}
			return res;
		}

		virtual int Write(char * buffer)
		{
			return 0;
		}

		virtual ~FileBufferReader()
		{
			PGE_CloseFile( m_hFile );
			delete m_pBuffer;
		}

	protected:

		PGE_FILE_HANDLE		m_hFile;
		const char*			m_pFileName;
		char*				m_pBuffer;
		int					m_dBufferSize;
		int					m_dBufferUse;
		int					m_dLength;
		int					m_dBufferPointer;

	};

	class FileWriter : public CBinaryStream
	{
	public:

		FileWriter( const char* filename )
		{
			m_pFileName = filename;
			m_hFile = PGE_OpenFile( m_pFileName, PGE_FILE_WRITE_CREATE );
		}

		virtual void Seek(int pos, PGE_WHENCE whence)
		{
			PGE_Seek32( m_hFile, pos, whence );
		}

		virtual int  GetPosition()
		{
			return PGE_Seek32( m_hFile, 0, PGE_SEEK_CUR );
		}

		virtual int GetLength()
		{
			int pos = GetPosition();
			int res = PGE_Seek32( m_hFile, 0, PGE_SEEK_END );
			PGE_Seek32( m_hFile, pos, PGE_SEEK_SET );
			return res;
		}

		virtual int BinaryRead(void * buffer, unsigned int size)
		{
			return 0;
		}

		virtual int BinaryWrite(void * buffer, unsigned int size)
		{
			return PGE_WriteBuffer( m_hFile, buffer, (int)size );
		}

		virtual int Read(char * buffer)
		{
			return 0;
		}

		virtual int Write(char * buffer)
		{
			register unsigned int length(0);
			while(1)
			{
				if( buffer[length++] == 0 )
					break;
			}
			return PGE_WriteBuffer( m_hFile, buffer, length );
		}

		virtual ~FileWriter()
		{
			PGE_CloseFile( m_hFile );
		}

	protected:

		PGE_FILE_HANDLE		m_hFile;
		const char*			m_pFileName;

	};

	class FileNormalRW : public CBinaryStream
	{
	public:

		FileNormalRW( const char* filename )
		{
			m_pFileName = filename;
			m_hFile = PGE_OpenFileRWCreate( filename );
		}

		virtual void Seek(int pos, PGE_WHENCE whence)
		{
			PGE_Seek32( m_hFile, pos, whence );
		}

		virtual int  GetPosition()
		{
			return PGE_Seek32( m_hFile, 0, PGE_SEEK_CUR );
		}

		virtual int GetLength()
		{
			int pos = GetPosition();
			int res = PGE_Seek32( m_hFile, 0, PGE_SEEK_END );
			PGE_Seek32( m_hFile, pos, PGE_SEEK_SET );
			return res;
		}

		virtual int BinaryRead(void * buffer, unsigned int size)
		{
			return PGE_ReadBuffer( m_hFile, buffer, (int)size );
		}

		virtual int BinaryWrite(void * buffer, unsigned int size)
		{
			return PGE_WriteBuffer( m_hFile, buffer, (int)size );
		}

		virtual int Read(char * buffer)
		{
			register int i(0);
			while(1)
			{
				if( PGE_ReadBuffer( m_hFile, buffer+i, 1 ) )
				{
					if( buffer[i] == 0 ) break;
				}
				else
				{
					buffer[i] = 0;
					break;
				}
				++i;
			}
			return i+1;
		}

		virtual int Write(char * buffer)
		{
			unsigned int length(0);
			while(1)
			{
				if( buffer[length++] == 0 )
					break;
			}
			return PGE_WriteBuffer( m_hFile, buffer, length );
		}

		virtual ~FileNormalRW()
		{
			PGE_CloseFile( m_hFile );
		}

	protected:

		PGE_FILE_HANDLE		m_hFile;
		const char*			m_pFileName;

	};

	class FileBufferRW : public CBinaryStream
	{
	public:

		FileBufferRW( const char* filename, unsigned int buffersize )
		{
			m_pFileName = filename;
			m_dBufferSize = buffersize;
			m_dBufferPointer = 0;
			m_dBufferUse = 0;
			m_pBuffer = new char[m_dBufferSize];
			m_hFile = PGE_OpenFileRWCreate( filename );
			m_dLength = PGE_Seek32( m_hFile, 0, PGE_SEEK_END );
			PGE_Seek32( m_hFile, 0, PGE_SEEK_SET );
			m_dBufferUse = PGE_ReadBuffer( m_hFile, m_pBuffer, m_dBufferSize );
		}

		virtual ~FileBufferRW()
		{
			PGE_CloseFile( m_hFile );
			delete m_pBuffer;
		}

		virtual int GetLength()
		{
			return m_dLength;
		}

		virtual int BinaryRead(void * buffer, unsigned int size)
		{
			if( m_dFilePointer >= m_dLength )
			{
				return 0;
			}
			if( (m_dFilePointer < m_dBufferPointer)||(m_dFilePointer >= m_dBufferPointer+m_dBufferUse) )
			{
				PGE_Seek32( m_hFile, m_dFilePointer, PGE_SEEK_SET );
				m_dBufferPointer = m_dFilePointer;
				m_dBufferUse = PGE_ReadBuffer( m_hFile, m_pBuffer, m_dBufferSize );
			}
			unsigned int availsize;
			register int res(0);
			register unsigned int i; 
			while(1)
			{
				availsize = m_dBufferUse + m_dBufferPointer - m_dFilePointer;
				if( size <= availsize )
				{
					for( i = 0; i < size; i++ )
					{
						((char*)buffer)[res++] = m_pBuffer[ (m_dFilePointer++) - m_dBufferPointer ];
					}
					return res;
				}
				else
				{
					size -= availsize;
					for( i = 0; i < availsize; i++ )
					{
						((char*)buffer)[res++] = m_pBuffer[ (m_dFilePointer++) - m_dBufferPointer ];
					}
					if( m_dFilePointer >= m_dLength )
					{
						return res;
					}
					PGE_Seek32( m_hFile, m_dFilePointer, PGE_SEEK_SET );
					m_dBufferPointer = m_dFilePointer;
					m_dBufferUse = PGE_ReadBuffer( m_hFile, m_pBuffer, m_dBufferSize );
				}

			}
			return res;
		}

		virtual int BinaryWrite(void * buffer, unsigned int size)
		{
			int pointerdistance = m_dFilePointer - m_dBufferPointer;
			if( pointerdistance >= 0 && pointerdistance < m_dBufferUse )
			{
				m_dBufferUse = pointerdistance;
			}
			PGE_Seek32( m_hFile, m_dFilePointer, PGE_SEEK_SET );
			int res = PGE_WriteBuffer( m_hFile, buffer, (int)size );
			m_dFilePointer += res;
			m_dLength = PGE_Seek32( m_hFile, 0, PGE_SEEK_END );
			return res;
		}

		virtual int Read(char * buffer)
		{
			if( m_dFilePointer >= m_dLength )
			{
				return 0;
			}
			if( (m_dFilePointer < m_dBufferPointer)||(m_dFilePointer >= m_dBufferPointer+m_dBufferUse) )
			{
				PGE_Seek32( m_hFile, m_dFilePointer, PGE_SEEK_SET );
				m_dBufferPointer = m_dFilePointer;
				m_dBufferUse = PGE_ReadBuffer( m_hFile, m_pBuffer, m_dBufferSize );
			}
			unsigned int availsize;
			register int res(0);
			register unsigned int i;
			while(1)
			{
				availsize = m_dBufferUse + m_dBufferPointer - m_dFilePointer;
				for( i = 0; i < availsize; i++ )
				{
					buffer[res++] = m_pBuffer[ (m_dFilePointer++) - m_dBufferPointer ];
					if( buffer[res-1] == 0 ) return res;
				}
				if( m_dFilePointer >= m_dLength )
				{
					buffer[res++] = 0;
					return res;
				}
				PGE_Seek32( m_hFile, m_dFilePointer, PGE_SEEK_SET );
				m_dBufferPointer = m_dFilePointer;
				m_dBufferUse = PGE_ReadBuffer( m_hFile, m_pBuffer, m_dBufferSize );
			}
			return res;
		}

		virtual int Write(char * buffer)
		{

			int pointerdistance = m_dFilePointer - m_dBufferPointer;
			if( pointerdistance >= 0 && pointerdistance < m_dBufferUse )
			{
				m_dBufferUse = pointerdistance;
			}
			PGE_Seek32( m_hFile, m_dFilePointer, PGE_SEEK_SET );
			register int i(0);
			do 
			{
				PGE_WriteBuffer( m_hFile, buffer+i, 1 );		
			}
			while( buffer[i++] != 0 );
			m_dFilePointer += i;
			m_dLength = PGE_Seek32( m_hFile, 0, PGE_SEEK_END );
			return i;
		}

	protected:

		PGE_FILE_HANDLE		m_hFile;
		const char*			m_pFileName;
		char*				m_pBuffer;
		int					m_dBufferSize;
		int					m_dBufferUse;
		int					m_dLength;
		int					m_dBufferPointer;

	};

	CFileStream::CFileStream( LPSTR filename, FILESTREAM_TYPE type, DWORD buffersize )
	{
		switch( type )
		{
		case FILE_READER:
			m_pFile = PGENew FileReader( filename );
			break;
		case FILE_BUFFER_READER:
			m_pFile = PGENew FileBufferReader( filename, buffersize );
			break;
		case FILE_WRITER:
			m_pFile = PGENew FileWriter( filename );
			break;
		case FILE_BUFFER_RW:
			m_pFile = PGENew FileBufferRW( filename, buffersize );
			break;
		case FILE_NORMAL_RW:
			m_pFile = PGENew FileNormalRW( filename );
			break;
		}
	}

	CFileStream::~CFileStream()
	{
		PGEDelete m_pFile;
	}

}
